package com.kuaiyin.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.util.Map;

@Slf4j
public class HttpClientUtils {

    private static CloseableHttpClient httpClient;
    private static final PoolingHttpClientConnectionManager connectionManager;
    private static final ObjectMapper objectMapper;  // Jackson's ObjectMapper

    // 默认的连接池配置
    private static final int MAX_TOTAL_CONNECTIONS = 200;
    private static final int MAX_CONNECTIONS_PER_ROUTE = 20;
    private static final int TIMEOUT = 5000; // 连接超时5秒，读取超时5秒
    private static final int MAX_RETRY_COUNT = 3; // 默认重试次数3次
    private static boolean RETRY_ENABLED = false; // 默认不开启重试

    // 初始化连接池和HttpClient
    static {
        connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS);
        connectionManager.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);

        // 设置超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(TIMEOUT)
                .setSocketTimeout(TIMEOUT)
                .build();

        // 创建带连接池的HttpClient
        httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .build();

        // 初始化 ObjectMapper
        objectMapper = new ObjectMapper();
    }

    // GET 请求 支持请求参数，返回 JSON 格式
    public static JsonNode doGet(String url, Map<String, Object> params, Map<String, Object> headers, Integer retryCount) throws IOException {
        if (retryCount != null) {
            enableRetry(retryCount); // 如果传入了重试次数，则开启重试
        }

        // 处理请求参数
        if (params != null && !params.isEmpty()) {
            StringBuilder urlWithParams = new StringBuilder(url);
            boolean isFirst = !url.contains("?");
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (isFirst) {
                    urlWithParams.append("?");
                    isFirst = false;
                } else {
                    urlWithParams.append("&");
                }
                urlWithParams.append(entry.getKey()).append("=").append(entry.getValue());
            }
            url = urlWithParams.toString();
        }

        HttpGet httpGet = new HttpGet(url);
        if (headers != null) {
            headers.forEach((key, value) -> httpGet.setHeader(key, value.toString()));
        }

        String response = executeRequest(httpGet);
        return parseJson(response);  // 解析为 JSON 返回
    }

    // POST 请求，返回 JSON 格式
    public static JsonNode doPost(String url, String jsonBody, Map<String, Object> headers, Integer retryCount) throws IOException {
        if (retryCount != null) {
            enableRetry(retryCount); // 如果传入了重试次数，则开启重试
        }
        HttpPost httpPost = new HttpPost(url);
        if (headers != null) {
            headers.forEach((key, value) -> httpPost.setHeader(key, value.toString()));
        }
        httpPost.setEntity(new StringEntity(jsonBody, "UTF-8"));
        String response = executeRequest(httpPost);
        return parseJson(response);  // 解析为 JSON 返回
    }

    // PUT 请求，返回 JSON 格式
    public static JsonNode doPut(String url, String jsonBody, Map<String, Object> headers, Integer retryCount) throws IOException {
        if (retryCount != null) {
            enableRetry(retryCount); // 如果传入了重试次数，则开启重试
        }
        HttpPut httpPut = new HttpPut(url);
        if (headers != null) {
            headers.forEach((key, value) -> httpPut.setHeader(key, value.toString()));
        }
        httpPut.setEntity(new StringEntity(jsonBody, "UTF-8"));
        String response = executeRequest(httpPut);
        return parseJson(response);  // 解析为 JSON 返回
    }

    // DELETE 请求，返回 JSON 格式
    public static JsonNode doDelete(String url, Map<String, Object> headers, Integer retryCount) throws IOException {
        if (retryCount != null) {
            enableRetry(retryCount); // 如果传入了重试次数，则开启重试
        }
        HttpDelete httpDelete = new HttpDelete(url);
        if (headers != null) {
            headers.forEach((key, value) -> httpDelete.setHeader(key, value.toString()));
        }
        String response = executeRequest(httpDelete);
        return parseJson(response);  // 解析为 JSON 返回
    }

    // 文件上传
    public static String uploadFile(String url, File file, Map<String, Object> headers, Integer retryCount) throws IOException {
        if (retryCount != null) {
            enableRetry(retryCount); // 如果传入了重试次数，则开启重试
        }
        // 上传文件的代码可以在此实现
        return null;
    }

    // 执行请求并返回响应体
    private static String executeRequest(HttpUriRequest request) throws IOException {
        try (CloseableHttpResponse response = httpClient.execute(request)) {
            HttpEntity entity = response.getEntity();
            return EntityUtils.toString(entity, "UTF-8");
        }
    }

    // 将响应字符串转换为 JSON
    private static JsonNode parseJson(String response) throws IOException {
        return objectMapper.readTree(response);  // 使用 Jackson 将响应字符串转为 JsonNode
    }

    // 关闭连接池
    public static void shutdown() {
        try {
            httpClient.close();
            connectionManager.shutdown();
        } catch (IOException e) {
            log.error("Failed to close HTTP client异常：", e);
        }
    }

    // 手动设置重试次数
    public static void enableRetry(int retryCount) {
        if (retryCount > 0) {
            RETRY_ENABLED = true;

            // 设置重试机制
            HttpRequestRetryHandler retryHandler = (exception, executionCount, context) -> {
                if (executionCount >= retryCount) {
                    return false; // 超过最大重试次数后不再重试
                }
                return exception instanceof org.apache.http.NoHttpResponseException; // 服务器无响应时重试
            };

            httpClient = HttpClients.custom()
                    .setConnectionManager(connectionManager)
                    .setRetryHandler(retryHandler)
                    .build();
        }
    }
}
